package nl.weeaboo.sh.editor.area;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

import nl.weeaboo.game.Log;
import nl.weeaboo.sh.io.AreaLoader;
import nl.weeaboo.sh.model.AreaModel;
import nl.weeaboo.sh.model.RoomEnemyModel;
import nl.weeaboo.sh.model.RoomModel;
import nl.weeaboo.sh.model.TileSetIndex;
import nl.weeaboo.sh.model.TileSetModel;
import timon.common.components.GuiUtil;
import timon.common.components.Skin;
import timon.common.components.TFileChooser;
import timon.common.io.FileUtil;
import timon.common.xml.XmlFile;

@SuppressWarnings("serial")
public class EditorFrame extends JFrame {

	private File file;
	private AreaModel area;
	private Map<String, EditorTileSet> tileSets;
	
	private RandomColors randomColors;
	private TilePanel tilePanel;
	private Palette palette;
	private AttributePanel attributePanel;
	
	public EditorFrame() {
		tileSets = new HashMap<String, EditorTileSet>();
		try {
			randomColors = RandomColors.fromImage();
		} catch (IOException ioe) {
			Log.showError(ioe);
		}
		
		palette = new Palette();		
		attributePanel = new AttributePanel();
		attributePanel.addChangeListener(new ChangeListener() {
			public void onChanged(Object object) {
				if (object instanceof RoomModel) {
					RoomModel room = (RoomModel)object;
					tilePanel.redraw();
					palette.onRoomChanged(room);
				}
			}
		});
		
		palette.addListener(new SelectionListener() {
			public void onSelected(Object object) {
				if (object instanceof TileSetIndex) {
					TileSetIndex index = (TileSetIndex)object;
					object = index.getTileSet().getTileModel(index.getX(), index.getY());
					tilePanel.setSelectedTileSetIndex(index);
				} else if (object instanceof RoomModel) {
					tilePanel.setSelectedRoom((RoomModel)object);
				} else if (object instanceof RoomEnemyModel) {
					tilePanel.setSelectedEnemy((RoomEnemyModel)object);
				} else {
					tilePanel.setSelectedTileSetIndex(null);					
					tilePanel.setSelectedRoom(null);
				}
				
				attributePanel.setSelected(area, object);				
			}
		});
		
		tilePanel = new TilePanel(randomColors, palette);		

		JPanel leftPanel = new JPanel(new BorderLayout(5, 5));
		leftPanel.add(tilePanel, BorderLayout.NORTH);
		leftPanel.add(palette, BorderLayout.CENTER);

		JPanel rightPanel = new JPanel(new BorderLayout(5, 5));
		rightPanel.add(attributePanel, BorderLayout.CENTER);
		
		setLayout(new BorderLayout(5, 5));
		add(leftPanel, BorderLayout.WEST);
		add(rightPanel, BorderLayout.CENTER);
		
		createMenuBar();
		
		pack();
		setTitle("Scarlet Heart Editor");
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		setPreferredSize(new Dimension(1024, 768));
		setLocationRelativeTo(null);
		setVisible(true);
	}
	
	//Functions
	public static void main(String args[]) throws IOException {
		try {
			GuiUtil.setSkin(Skin.NATIVE);
		} catch (Exception e) {
			Log.warning(e);
		}

		EditorFrame ef = new EditorFrame();
		ef.open("res/level/1/area00.xml");		
	}
	
	public void dispose() {		
		saveTileSets();
		
		tileSets.clear();
		palette.dispose();

		System.out.println("Exiting...");
		
		super.dispose();
	}
	
	protected void saveTileSets() {
		for (EditorTileSet ets : tileSets.values()) {
			XmlFile xmlfile = new XmlFile("tileSet");
			ets.getModel().save(xmlfile.getRoot());
			try {
				String name = String.format("res/tiles/%s.xml", ets.getId());
				System.out.printf("Saving tileset: %s...\n", name);
				FileUtil.write(name, xmlfile.toXmlString());
			} catch (IOException e) {
				Log.showError(e);
			}
		}		
	}
	
	protected void createMenuBar() {
		JMenuBar menuBar = new JMenuBar();
		
		JMenuItem openItem = new JMenuItem("Open");
		openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
		openItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				open();
			}
		});
		
		JMenuItem saveItem = new JMenuItem("Save");
		saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
		saveItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				save();
			}
		});
		
		JMenu fileMenu = new JMenu("File");
		fileMenu.add(openItem);
		fileMenu.add(saveItem);
		menuBar.add(fileMenu);
		
		setJMenuBar(menuBar);
	}
	
	public void open() {
		TFileChooser filec = new TFileChooser();
		filec.setDialogType(TFileChooser.DialogType.AWT);
		filec.setMode(TFileChooser.Mode.OPEN);
		filec.setPath(file != null ? file.getAbsolutePath() : ".");
		
		if (filec.showDialog(this) == TFileChooser.OK_OPTION
				&& filec.getSelectedFile() != null)
		{
			try {
				open(filec.getSelectedFile().getAbsolutePath());
			} catch (IOException ioe) {
				Log.showError(ioe);
			}
		}
	}
		
	public void open(String path) throws IOException {
		saveTileSets();

		AreaLoader loader = new AreaLoader();
		AreaModel model = loader.load(path);
		
		file = new File(path);
		setArea(model);
	}
	
	public void save() {
		TFileChooser filec = new TFileChooser();
		filec.setDialogType(TFileChooser.DialogType.AWT);
		filec.setMode(TFileChooser.Mode.SAVE);
		filec.setPath(file != null ? file.getAbsolutePath() : ".");
		
		if (filec.showDialog(this) == TFileChooser.OK_OPTION
				&& filec.getSelectedFile() != null)
		{
			file = filec.getSelectedFile();

			try {
				saveTileSets();
				FileUtil.write(file.getAbsolutePath(), area.save().toXmlString());
			} catch (IOException e) {
				Log.showError(e);
			}
		}
	}
	
	//Getters
	
	//Setters
	public void setArea(AreaModel model) {
		if (area != model) {
			tileSets.clear();

			area = model;
			for (TileSetModel tsm : area.getTileSets().values()) {
				try {
					EditorTileSet ets = EditorTileSet.load(tsm);
					tileSets.put(ets.getId(), ets);
				} catch (IOException ioe) {
					Log.error(ioe);
				}
			}
			tilePanel.setArea(area, tileSets);			
			palette.setArea(area, tileSets);
		}
	}
	
}
